package service

import (
	"crypto/sha256"
	"encoding/json"
	"fmt"
	config "gitee.com/lanshiren/miniprogram/app/conf"
	"gitee.com/lanshiren/miniprogram/app/model"
	"github.com/gomodule/redigo/redis"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

type AuthResult struct {
	Openid     string `json:"openid"`
	SessionKey string `json:"session_key"`
	Unionid    string `json:"unionid"`
	Errcode    int    `json:"errcode"`
	Errmsg     string `json:"errmsg"`
}

// 小程序登录凭证校验 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
// code: 小程序端通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器
// AuthResult: 认证的结果
func WxJsCode2Session(code string) (AuthResult, error) {
	// openid
	params := url.Values{}
	Url, err := url.Parse("https://api.weixin.qq.com/sns/jscode2session")
	if err != nil {
		return AuthResult{}, err
	}
	params.Set("appid", config.Conf.AppID)
	params.Set("secret", config.Conf.Secret)
	params.Set("js_code", code)
	params.Set("grant_type", "authorization_code")
	Url.RawQuery = params.Encode()
	urlPath := Url.String()
	resp, err := http.Get(urlPath)
	if resp == nil {
		return AuthResult{}, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return AuthResult{}, err
	}
	defer resp.Body.Close()
	var res AuthResult
	if err := json.Unmarshal(body, &res); err != nil {
		return AuthResult{}, err
	}
	return res, err
}

// GenToken ...
func GenToken(authStr string) (token string) {
	h := sha256.New()
	h.Write([]byte(authStr))
	return fmt.Sprintf("%x", h.Sum(nil))
}

// SaveSession ...
func SaveSession(ttl uint64, token, userData string) error {
	conn := Pool.Get()
	defer conn.Close()
	_, err := conn.Do("SETEX", token, ttl, userData)
	if err != nil {
		return err
	}
	return nil
}

// GetOpenIdByToken ...
func GetOpenIdByToken(token string) (string, error) {
	conn := Pool.Get()
	defer conn.Close()
	userData, err := redis.String(conn.Do("GET", "session-"+token))
	if err != nil {
		return "", err
	}
	return strings.Split(userData, "$")[0], nil
}

// TryGetUserSession ...
func TryGetUserSession(token string) (string, error) {
	conn := Pool.Get()
	defer conn.Close()
	userData, err := redis.String(conn.Do("GET", token))
	if err != nil {
		return "", err
	}
	return userData, nil
}

// HasUserRegisterActivity ...
func HasUserRegisterActivity(userId, acId uint) (bool, bool, error) {
	rss, err := model.GetRegistrationByUIDAndAcID(userId, acId)
	if err != nil {
		return false, false, err
	}
	if len(rss) > 0 {
		return true, rss[0].Status == model.RegistrationDone, nil
	}
	return false, false, nil
}

// UpdateRegisterUserCount ...
func UpdateRegisterUserCount(acId uint) error {
	rss, err := model.GetRegistrationListByAcID(acId)
	if err != nil {
		return err
	}
	return model.QueryAndUpdateAcCurCount(acId, len(rss))
}
